/*NOTICE

This software was produced for the U. S. Government
under Contract No. FA8721-09-C-0002, and is
subject to the Rights in Noncommercial Computer Software
and Noncommercial Computer Software Documentation Clause
(DFARS) 252.227-7014 (JUN 1995)

(c) 2009 The MITRE Corporation. All Rights Reserved.
*/
package org.mitre.xmltransform;

import java.io.File;
import java.io.FileWriter;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;

public class XmlOutputDocument {

	public XmlOutputDocument(File pOutputFile) {
		try {
			mOutputFile = pOutputFile;
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setNamespaceAware(true); // XPath's with namespace won't work if you don't make this true
			mXmlOutputDocument = dbf.newDocumentBuilder().newDocument();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public Attr createAttributeNS(String pNamespace, String pName) {
		Attr attrib = mXmlOutputDocument.createAttributeNS(pNamespace, pName);

		
		return attrib;
	}
	
	public void addXmlSnippet(Node pParent, String pXml) {
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setNamespaceAware(true); // XPath's with namespace won't work if you don't make this true
	        DocumentBuilder xmlBuilder = dbf.newDocumentBuilder();
	        Document doc = xmlBuilder.parse(new InputSource(new StringReader(pXml)));
	        NodeList children = doc.getChildNodes();
	        Node child, adoptedNode;
	        for (int i = 0; i < children.getLength(); i++) {
	        	child = children.item(i);
	        	//child = doc.removeChild(child);
	        	adoptedNode = pParent.getOwnerDocument().importNode(child, true);
	        	pParent.appendChild(adoptedNode);
	        }
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
		
	public Element addRootElement(String pName, String pValue) {
		return addRootElement(null, pName, pValue);
	}
	public Element addRootElement(String pNamespaceUri, String pName, String pValue) {
		return addElement(null, pNamespaceUri, pName, pValue);
	}
	
	public Element addElement(Node pParent, String pName, String pValue) {
		return addElement(pParent, null, pName, pValue);
	}
	public Element addElement(Node pParent, String pNamespaceUri, String pName, String pValue) {
		Element newElem;
		if (pNamespaceUri == null) {
			newElem = mXmlOutputDocument.createElement(pName);
		} else {
			newElem = mXmlOutputDocument.createElementNS(pNamespaceUri, pName);
		}
		Node parent = (pParent == null) ? mXmlOutputDocument : pParent;
		parent.appendChild(newElem);
		if (pValue != null) {
			Text text = mXmlOutputDocument.createTextNode(pValue);
			newElem.appendChild(text);
		}
		return newElem;
	}

	public boolean writeOutput() {
		try {
			FileWriter writer = new FileWriter(mOutputFile);
			//StringWriter strWriter = new StringWriter();
			DOMSource src = new DOMSource(mXmlOutputDocument);
			Result result = new StreamResult(writer);
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer tx = transformerFactory.newTransformer();
			tx.setOutputProperty(OutputKeys.INDENT, "yes");
			//tx.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			tx.transform(src, result);
			writer.flush();
			writer.close();
			//System.out.println(strWriter.getBuffer().toString());
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	public String getOutputFileName() {
		return mOutputFile.getName();
	}
	
	public String getNextId() {
		return "ID" + cNextId++;
	}
	
	public String getLastId() {
		return "ID" + (cNextId-1);
	}
	
	public void finishDocument() {
	}


	private static int cNextId = 1;
	private File mOutputFile;
	private Document mXmlOutputDocument;
}
